home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 4 / Example 4.3 / heightMap.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-07-11  |  8.0 KB  |  303 lines

  1. #include "heightMap.h"
  2. #include "debug.h"
  3.  
  4. const DWORD PARTICLE::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;
  5. DWORD FtoDword(float f){return *((DWORD*)&f);}
  6.  
  7. float Noise(int x)
  8. {
  9.     x = (x<<13) ^ x;
  10.     return (1.0 - ((x * (x*x * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);    
  11. }
  12.  
  13. float CosInterpolate(float v1, float v2, float a)
  14. {
  15.     float angle = a * D3DX_PI;
  16.     float prc = (1.0f - cos(angle)) * 0.5f;
  17.     return  v1*(1.0f - prc) + v2*prc;
  18. }
  19.  
  20. HEIGHTMAP::HEIGHTMAP(IDirect3DDevice9* Dev, INTPOINT _size)
  21. {
  22.     try
  23.     {
  24.         m_pDevice = Dev;
  25.         m_size = _size;
  26.  
  27.         // Init m_pSprite
  28.         D3DXCreateSprite(m_pDevice,&m_pSprite);
  29.  
  30.         //Reset the heightMap to 0
  31.         m_maxHeight = 15.0f;
  32.         m_pHeightMap = new float[m_size.x * m_size.y];
  33.         memset(m_pHeightMap, 0, sizeof(float)*m_size.x*m_size.y);
  34.  
  35.         m_selRect.top = m_selRect.left = m_size.x / 2 - 5;
  36.         m_selRect.bottom = m_selRect.right = m_size.x / 2 + 5;
  37.  
  38.         //Set particle vertex buffer and texture to NULL
  39.         m_pVb = NULL;
  40.         m_pHeightMapTexture = NULL;
  41.     }
  42.     catch(...)
  43.     {
  44.         debug.Print("Error in HEIGHTMAP::HEIGHTMAP()");
  45.     }
  46. }
  47.  
  48. HEIGHTMAP::~HEIGHTMAP()
  49. {
  50.     Release();
  51. }
  52.  
  53. void HEIGHTMAP::Release()
  54. {
  55.     if(m_pHeightMap != NULL)delete [] m_pHeightMap;
  56.     if(m_pVb != NULL)m_pVb->Release();
  57.     if(m_pSprite != NULL)m_pSprite->Release();
  58.     if(m_pHeightMapTexture != NULL)m_pHeightMapTexture->Release();
  59. }
  60.  
  61. HRESULT HEIGHTMAP::LoadFromFile(char fileName[])
  62. {
  63.     try
  64.     {
  65.         //Reset the heightMap to 0
  66.         memset(m_pHeightMap, 0, sizeof(float) * m_size.x * m_size.y);
  67.  
  68.         //Initiate the texture variables
  69.         if(m_pHeightMapTexture != NULL)m_pHeightMapTexture->Release();
  70.         m_pHeightMapTexture = NULL;
  71.         D3DXIMAGE_INFO info;
  72.  
  73.         //Load the texture (and scale it to our heightMap m_size)
  74.         if(FAILED(D3DXCreateTextureFromFileEx(m_pDevice, fileName, m_size.x, m_size.y, 1, D3DUSAGE_DYNAMIC, 
  75.                                             D3DFMT_L8, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 
  76.                                             NULL, &info, NULL, &m_pHeightMapTexture)))return E_FAIL;
  77.  
  78.         //Lock the texture
  79.         D3DLOCKED_RECT sRect;
  80.         m_pHeightMapTexture->LockRect(0, &sRect, NULL, NULL);
  81.         BYTE *bytes = (BYTE*)sRect.pBits;
  82.  
  83.         //Extract height values from the texture
  84.         for(int y=0;y<m_size.y;y++)
  85.             for(int x=0;x<m_size.x;x++)
  86.                 {
  87.                     BYTE *b = bytes + y * sRect.Pitch + x;
  88.                     m_pHeightMap[x + y * m_size.x] = ((float)*b / 255.0f) * m_maxHeight;
  89.                 }
  90.                         
  91.         //Unlock the texture
  92.         m_pHeightMapTexture->UnlockRect(0);
  93.     }
  94.     catch(...)
  95.     {
  96.         debug.Print("Error in HEIGHTMAP::LoadFromFile()");
  97.     }
  98.  
  99.     return S_OK;
  100. }
  101.  
  102. HRESULT HEIGHTMAP::CreateRandomHeightMap(int seed, float noiseSize, float persistence, int octaves)
  103. {
  104.     if(m_pHeightMapTexture != NULL){m_pHeightMapTexture->Release(); m_pHeightMapTexture = NULL;}
  105.     m_pDevice->CreateTexture(m_size.x, m_size.y, 1, D3DUSAGE_DYNAMIC, D3DFMT_L8, D3DPOOL_DEFAULT, &m_pHeightMapTexture, NULL);
  106.  
  107.     D3DLOCKED_RECT lock;
  108.     m_pHeightMapTexture->LockRect(0, &lock, NULL, NULL);
  109.  
  110.     //For each map node
  111.     for(int y=0;y<m_size.y;y++)
  112.         for(int x=0;x<m_size.x;x++)
  113.         {
  114.             //Scale x & y to the range of 0.0 - m_size
  115.             float xf = ((float)x / (float)m_size.x) * noiseSize;
  116.             float yf = ((float)y / (float)m_size.y) * noiseSize;
  117.  
  118.             float total = 0;            
  119.  
  120.             // For each octave
  121.             for(int i=0;i<octaves;i++)
  122.             {
  123.                 //Calculate frequency and amplitude (different for each octave)
  124.                 float freq = pow(2, i);
  125.                 float amp = pow(persistence, i);
  126.  
  127.                 //Calculate the x,y noise coordinates
  128.                 float tx = xf * freq;
  129.                 float ty = yf * freq;
  130.                 int tx_int = tx;
  131.                 int ty_int = ty;
  132.  
  133.                 //Calculate the fractions of x & y
  134.                 float fracX = tx - tx_int;
  135.                 float fracY = ty - ty_int;
  136.  
  137.                 //Get the noise of this octave for each of these 4 points
  138.                 float v1 = Noise(tx_int + ty_int * 57 + seed);
  139.                 float v2 = Noise(tx_int+ 1 + ty_int * 57 + seed);
  140.                 float v3 = Noise(tx_int + (ty_int+1) * 57 + seed);
  141.                 float v4 = Noise(tx_int + 1 + (ty_int+1) * 57 + seed);
  142.  
  143.                 //Smooth in the X-axis
  144.                 float i1 = CosInterpolate(v1 , v2 , fracX);
  145.                 float i2 = CosInterpolate(v3 , v4 , fracX);
  146.  
  147.                 //Smooth in the Y-axis
  148.                 total += CosInterpolate(i1 , i2 , fracY) * amp;
  149.             }
  150.  
  151.             int b = 128 + total * 128.0f;
  152.             if(b < 0)b = 0;
  153.             if(b > 255)b = 255;
  154.  
  155.             BYTE *bDest = (BYTE*)lock.pBits;
  156.             bDest += y * lock.Pitch + x;
  157.             *bDest = b;
  158.  
  159.             //Save to heightMap
  160.             m_pHeightMap[x + y * m_size.x] = ((float)b / 255.0f) * m_maxHeight;
  161.         }
  162.  
  163.     m_pHeightMapTexture->UnlockRect(0);
  164.  
  165.     return S_OK;
  166. }
  167.  
  168. void HEIGHTMAP::RaiseTerrain(RECT r, float f)
  169. {
  170.     for(int y=r.top;y<=r.bottom;y++)
  171.         for(int x=r.left;x<=r.right;x++)
  172.         {
  173.             m_pHeightMap[x + y * m_size.x] += f;
  174.             if(m_pHeightMap[x + y * m_size.x] < -m_maxHeight)m_pHeightMap[x + y * m_size.x] = -m_maxHeight;
  175.             if(m_pHeightMap[x + y * m_size.x] > m_maxHeight)m_pHeightMap[x + y * m_size.x] = m_maxHeight;
  176.         }
  177.  
  178.     CreateParticles();
  179. }
  180.  
  181. void HEIGHTMAP::SmoothTerrain()
  182. {
  183.     //Create temporary heightmap
  184.     float *hm = new float[m_size.x * m_size.y];
  185.     memset(hm, 0, sizeof(float) * m_size.x * m_size.y);
  186.  
  187.     for(int y=0;y<m_size.y;y++)
  188.         for(int x=0;x<m_size.x;x++)
  189.         {
  190.             float totalHeight = 0.0f;
  191.             int noNodes = 0;
  192.  
  193.             //Add all neighboring heights together and use the average
  194.             for(int y1=y-1;y1<=y+1;y1++)
  195.                 for(int x1=x-1;x1<=x+1;x1++)
  196.                     if(x1 >= 0 && x1 < m_size.x && y1 >= 0 && y1 < m_size.y)
  197.                     {
  198.                         totalHeight += m_pHeightMap[x1 + y1 * m_size.x];
  199.                         noNodes++;
  200.                     }
  201.  
  202.             hm[x + y * m_size.x] = totalHeight / (float)noNodes;
  203.         }
  204.  
  205.     //Replace old heightmap with smoothed heightmap
  206.     delete [] m_pHeightMap;
  207.     m_pHeightMap = hm;        
  208.  
  209.     CreateParticles();
  210.  
  211.     Sleep(500);
  212. }
  213.  
  214. void HEIGHTMAP::MoveRect(int dir)
  215. {
  216.     if(dir == LEFT)    {m_selRect.left--;m_selRect.right--;}
  217.     if(dir == RIGHT){m_selRect.left++;m_selRect.right++;}
  218.     if(dir == UP)    {m_selRect.top--;m_selRect.bottom--;}
  219.     if(dir == DOWN)    {m_selRect.top++;m_selRect.bottom++;}
  220.  
  221.     Sleep(100);
  222.     CreateParticles();
  223. }
  224.  
  225. HRESULT HEIGHTMAP::CreateParticles()
  226. {
  227.     try
  228.     {
  229.         if(m_pVb != NULL)
  230.         {
  231.             m_pVb->Release();
  232.             m_pVb = NULL;
  233.         }
  234.  
  235.         if(FAILED(m_pDevice->CreateVertexBuffer(m_size.x * m_size.y * sizeof(PARTICLE), D3DUSAGE_DYNAMIC | D3DUSAGE_POINTS | D3DUSAGE_WRITEONLY, PARTICLE::FVF, D3DPOOL_DEFAULT, &m_pVb, 0)))
  236.             debug.Print("Failed to create particle vertex buffer");
  237.  
  238.         PARTICLE *v = NULL;
  239.         m_pVb->Lock(0, 0, (void**)&v, D3DLOCK_DISCARD);
  240.  
  241.         for(int y=0;y<m_size.y;y++)
  242.             for(int x=0;x<m_size.x;x++)
  243.             {
  244.                 float prc = m_pHeightMap[x + y * m_size.x] / m_maxHeight;
  245.                 if(prc < 0.0f)prc = -prc;
  246.                 int red =  255 * prc;
  247.                 int green = 255 * (1.0f - prc);
  248.                 
  249.                 if(x >= m_selRect.left && x <= m_selRect.right && y >= m_selRect.top && y <= m_selRect.bottom)
  250.                     v->color = D3DCOLOR_ARGB(255, 0, 0, 255);
  251.                 else v->color = D3DCOLOR_ARGB(255, red, green, 0);
  252.  
  253.                 v->position = D3DXVECTOR3(x, m_pHeightMap[x + y * m_size.x], -y);
  254.                 v++;
  255.             }
  256.         
  257.         m_pVb->Unlock();
  258.  
  259.     }
  260.     catch(...)
  261.     {
  262.         debug.Print("Error in HEIGHTMAP::CreateParticles()");
  263.         return E_FAIL;
  264.     }
  265.  
  266.     return S_OK;
  267. }
  268.  
  269. void HEIGHTMAP::Render()
  270. {
  271.     try
  272.     {
  273.         if(m_pVb != NULL)
  274.         {
  275.             m_pDevice->SetRenderState(D3DRS_LIGHTING, false);
  276.             m_pDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, true);
  277.             m_pDevice->SetRenderState(D3DRS_POINTSCALEENABLE, true);
  278.  
  279.             m_pDevice->SetRenderState(D3DRS_POINTSIZE, FtoDword(0.7f));
  280.             m_pDevice->SetRenderState(D3DRS_POINTSIZE_MIN, FtoDword(0.0f));
  281.             m_pDevice->SetRenderState(D3DRS_POINTSCALE_A, 0);
  282.             m_pDevice->SetRenderState(D3DRS_POINTSCALE_B, FtoDword(0.0f));
  283.             m_pDevice->SetRenderState(D3DRS_POINTSCALE_C, FtoDword(1.0f));
  284.             m_pDevice->SetRenderState(D3DRS_ZWRITEENABLE, true);
  285.  
  286.             m_pDevice->SetTexture(0, NULL);
  287.             m_pDevice->SetFVF(PARTICLE::FVF);
  288.             m_pDevice->SetStreamSource(0, m_pVb, 0, sizeof(PARTICLE));
  289.             m_pDevice->DrawPrimitive(D3DPT_POINTLIST, 0, m_size.x * m_size.y);
  290.         }
  291.  
  292.         if(m_pSprite != NULL)
  293.         {
  294.             m_pSprite->Begin(0);
  295.             m_pSprite->Draw(m_pHeightMapTexture, NULL, NULL, &D3DXVECTOR3(1.0f, 1.0f, 1.0f), 0xffffffff);
  296.             m_pSprite->End();    
  297.         }
  298.     }
  299.     catch(...)
  300.     {
  301.         debug.Print("Error in HEIGHTMAP::Render()");
  302.     }
  303. }